package com.sojpt.boot;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.jfinal.aop.Invocation;
import com.jfinal.core.Action;
import com.jfinal.core.ActionHandler;
import com.jfinal.core.ActionReporter;
import com.jfinal.core.Controller;
import com.jfinal.render.Render;

@Aspect
@Component
@Order(10)
@EnableConfigurationProperties(ActiveRecordPluginProperties.class)
public class SoJptControllerAspectConfig {

	@Autowired
	private ActiveRecordPluginProperties arpProperties;

	/**
	 * *匹配带有 AdminOnlyMethod Annotation的方法
	 */
	@Pointcut("execution(public * com.jfinal.core.Controller+.*(..))")
	public void sojptMethod() {
		
	}

	@Around("sojptMethod()")
	public Object around(ProceedingJoinPoint jp) throws Throwable {

		Object obj = null;

		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

		HttpServletRequest request = requestAttributes.getRequest();
		HttpServletResponse response = requestAttributes.getResponse();
		
		SoJptBoot.jFinalFilter.doFilter(request, response, SoJptBoot.soJptBootFilterChain);
		
		String[] urlPara = { null };
		String target = request.getRequestURI();
		
		Action action = ActionHandler.actionMapping.getAction(target, urlPara);


		Method method = jp.getTarget().getClass().getMethod("_init_", Action.class, HttpServletRequest.class, HttpServletResponse.class, String.class);
		method.invoke(jp.getTarget(), action, request, response, urlPara[0]);

		Controller controller = ActionHandler.controllerFactory.getController(action.getControllerClass());
		if (ActionHandler.injectDependency) {com.jfinal.aop.Aop.inject(controller);}
		controller._init_(action, request, response, urlPara[0]);
		
		if (arpProperties.getIsDevMode()) {
			if (ActionReporter.isReportAfterInvocation(request)) {
				obj = new Invocation(action, controller).invoke(jp);
				ActionReporter.report(target, controller, action);
			} else {
				ActionReporter.report(target, controller, action);
				obj = new Invocation(action, controller).invoke(jp);
			}
		} else {
			obj = new Invocation(action, controller).invoke(jp);
		}

		Render render = (Render) jp.getTarget().getClass().getMethod("getRender").invoke(jp.getTarget());
		if (render != null) { //controller使用了render方法
			HttpServletRequest request2 = (HttpServletRequest) jp.getTarget().getClass().getMethod("getRequest").invoke(jp.getTarget());
			HttpServletResponse response2 = (HttpServletResponse) jp.getTarget().getClass().getMethod("getResponse").invoke(jp.getTarget());

			render.setContext(request2, response2);

			// 解决undertow 下并发 java.util.ConcurrentModificationException
			List<String> attrList = new ArrayList<>();

			try {
				Enumeration<String> e = request.getAttributeNames();// 返回Enumeration对象
				while (e.hasMoreElements()) {

					String value = (String) e.nextElement();// 调用nextElement方法获得元素
					if (value.contains("."))
						attrList.add(value);
				}

				// 移除SpringBoot requset的内置属性
				for (String value : attrList) {
					request.removeAttribute(value);
				}

				render.render();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		return obj;
	}

}